home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 11879 < prev    next >
Encoding:
Text File  |  1996-08-05  |  3.6 KB  |  138 lines

  1. Path: vixen.cso.uiuc.edu!usenet
  2. From: n-dade@uiuc.edu
  3. Newsgroups: comp.lang.c++
  4. Subject: Q: when are temporaries constructed inside a :? destroyed
  5. Date: 16 Mar 1996 21:11:17 GMT
  6. Organization: University of Illinois at Urbana
  7. Message-ID: <4ifapl$2lq@vixen.cso.uiuc.edu>
  8. Reply-To: n-dade@uiuc.edu
  9. NNTP-Posting-Host: homer.apr.uiuc.edu
  10. X-Newsreader: IBM NewsReader/2 v1.2
  11.  
  12.  
  13. function( xyz ? abc : object1.GetCopyOfObject2().GetSomethingFromObject2() );
  14.  
  15.  
  16. I was debugging code like above and I realized that the compiler
  17. (IBM's VA C++) was destroying the temporary object generated during the
  18. evaluation of the ?: (there's a temporary "Object2") before the call to
  19. function(). I took the same code and compiled it on a different
  20. compiler (MS's C++) and the code it generated saved the direction of the
  21. ?: in another temporary variable, and destroyed the temporary object at
  22. after the call to function()cout if the temporary object had been
  23. constructed.
  24.  
  25. I had expected the second behavior, but I can't find anything
  26. in my C++ references that defines which behavior is legal.
  27.  
  28. Here's the code I used to test this:
  29.  
  30. /*-----------------------------------------------------------*/
  31.  
  32. #include "iostream.h"
  33. #include "string.h"
  34.  
  35. class A {                        // a "string" class
  36.    char* text;
  37.  public:
  38.    A(const char* t) {
  39.       cout << "A(\"" << t << "\")" << endl;
  40.       int len = strlen(t);
  41.       text = new char[len+1];
  42.       strncpy(text,t,len+1);
  43.    }
  44.  
  45.    A(const A& a) {
  46.       cout << "A(A&) (\"" << a.text << "\")" << endl;
  47.       int len = strlen(a.text);
  48.       text = new char[len+1];
  49.       strncpy(text,a.text,len+1);
  50.    }
  51.  
  52.    ~A() {
  53.       static char c = 'A';
  54.       cout << "~A() using " << c << endl;
  55.       // instead of deleting the text I fill it with a known pattern
  56.       // that way I can tell if something below uses this "freed" memory
  57.       for(int i=0; text[i]; i++) text[i] = c;
  58.       c++;
  59.    }
  60.  
  61.    const char* QueryText() const { return text; }  // return pointer to private char[]
  62. };
  63.  
  64. class B {                           // something that has a "string" in it
  65.    A a;
  66.  public:
  67.    B(const char* str) : a(str) {}
  68.  
  69.    A QueryA() const { return a; }    // ask for its string
  70. };
  71.  
  72. main(int argc, char *argv[])
  73. {
  74.    // create a B
  75.    B b ("some text");         
  76.  
  77.    // and output its string if no arguments were given
  78.    cout << ( argc>1 ? "argc was > 1" : b.QueryA().QueryText() )
  79.         << endl;
  80.  
  81.    return 0;
  82. }
  83.  
  84. /*-----------------------------------------------------------*/
  85.  
  86. The statement of interest is the cout in main(): The first compiler
  87. generates:
  88.  
  89. make room on stack for a char* named "temp1"
  90. if argc > 1 {
  91.    temp1 = "argc was > 1";
  92. } else {
  93.    make room on stack for an A named "temp2"
  94.    pass &temp2 to b.QueryA() so QueryA constructs temp2 using A(const A& b.a)
  95.    temp1 = temp2.QueryText()
  96.    destroy temp2 using ~A()
  97.    pop the room for temp2 off the stack
  98. }
  99. operator<< (ostream& cout, const char* temp1)
  100.  
  101. So the output is:
  102. A("some text")
  103. A(A&) ("some text")
  104. ~A() using A
  105. AAAAAAAAA
  106. ~A() using B
  107.  
  108.  
  109. The second compiler generates:
  110.  
  111. make room on stack for a char* named "temp1" an A named "temp2"
  112.  and an int named "temp3"
  113. temp3 = (argc > 1)
  114. if temp3 {
  115.    temp1 = "argc was > 1";
  116. } else {
  117.    pass &temp2 to b.QueryA() so QueryA constructs temp2 using A(const A& b.a)
  118.    temp1 = temp2.QueryText()
  119. }
  120. operator<< (ostream& cout, const char* temp1)
  121. if (temp3) {
  122.    destroy temp2 using ~A()
  123. }
  124. pop temp1, 2 and 3 off the stack
  125.  
  126. So the output is:
  127. A("some text")
  128. A(A&) ("some text")
  129. some text
  130. ~A() using A
  131. ~A() using B
  132.  
  133.  
  134. Which is the correct behavior? Or are they both considered correct?
  135.  
  136. -Nicolas Dade / n9rzb / nicolas-dade@uiuc.edu
  137.  
  138.